// 世界BOSS期望存活轮数
var ALIVE_ROUND_EXPECT = 5;
var ALIVE_ROUND_MAX = 15;

// 世界BOSS
function WorldBoss() { 

    this.worldboss = {
        /*
            init_blood:0,       //初始血量
            blood:0,            //当前血量
            fight_times:0,      //战斗次数
            damage_factor:0,    //当前伤害系数

            info$id: {          //上一次today_id为$id的信息
                alive_time:0,       //存活时长
                damage_factor:0,    //伤害系数 
            },

            kill:0,
            kill_reward:0,
            top: [{'uid':0, 'hurt':0}],
            day:0, 
            today_id:0,
        */
    };

    this.hurts = {};
    this.updates = {}; 
    this.sortTime = {};
    this.schedule = {};
} 
 
WorldBoss.create = function() { 
    gDBWorld.insert({_id: 'world_boss', world_boss: {}}, function(err, result){}); 
}; 
 
WorldBoss.prototype = { 
     
    init: function(callback) { 
        gDBWorld.findOne({_id : 'world_boss'}, {}, function(err, doc){ 
            if( doc ) {
                this.worldboss = doc.world_boss;
                this._init();
                callback && callback(true);
            }else{
                callback && callback(false);
            }    
        }.bind(this));
    },

    _init: function() {
        var worldboss = this.worldboss;

        if (!worldboss.hasOwnProperty('init_blood')) {
            worldboss.init_blood = gConfGlobal.WorldBossMaxHealth;
            this.addUpdate('world_boss.init_blood', worldboss.init_blood);
        }

        if (!worldboss.hasOwnProperty('blood')) {
            worldboss.blood = worldboss.init_blood;
            this.addUpdate('world_boss.blood', worldboss.blood);
        }

        if (!worldboss.hasOwnProperty('fight_times')) {
            worldboss.fight_times = 0;
            this.addUpdate('world_boss.fight_times', worldboss.fight_times);
        }

        if (!worldboss.hasOwnProperty('damage_factor')) {
            worldboss.damage_factor = 1;
            this.addUpdate('world_boss.damage_factor', worldboss.damage_factor);
        }


        for (var i = 1; i <= 2; ++i) {
            var infoName = 'info' + i;
            var info = worldboss[infoName];
            if (!info) {
                info = {
                    'alive_time': worldboss.alive_time || ALIVE_ROUND_EXPECT*gConfGlobal.WorldBossCoolTime,
                    'damage_factor': worldboss.damage_factor,
                }
                worldboss[infoName] = info;
                this.addUpdate('world_boss.'+infoName, info); 
            }
        }

        this.updateBoss();
        this.save();

        if( !worldboss.top ) return;
        var hurts = {};
        this.hurts = hurts;
        worldboss.top.forEach(function(user){
            hurts[user.uid] = user.hurt;
        });
    },

    updateBoss: function() {
        
        //计算周期
        var now = new Date();
        var schedule = {day:now.getDateNumber(), id:0, keep:false};
        var todaySeconds = now.getTodaySeconds();
        if (todaySeconds < (gConfGlobal.WorldBossStartHour1*3600 - 10)) {
            schedule.id = 0;
            schedule.keep = false;
        } else if (todaySeconds < (gConfGlobal.WorldBossEndHour1*3600 + 10)) {
            schedule.id = 1;
            schedule.keep = true;
        } else if (todaySeconds < (gConfGlobal.WorldBossStartHour2*3600 - 10)) {
            schedule.id = 1;
            schedule.keep = false;
        } else if (todaySeconds < (gConfGlobal.WorldBossEndHour2*3600 + 10)) {
            schedule.id = 2;
            schedule.keep = true;
        } else {
            schedule.id = 2;
            schedule.keep = false;
        }
        this.schedule = schedule;

        // 更新worldboss
        var worldboss = this.worldboss;
        if (schedule.id && ((schedule.id != worldboss.today_id) || (schedule.day != worldboss.day))) {
            var initAttribute = this.getTodayBossAttrbute();
            this.hurts = {};

            var worldboss = this.worldboss;
            worldboss.init_blood = initAttribute.blood;
            worldboss.blood = initAttribute.blood;
            worldboss.fight_times = 0;
            worldboss.damage_factor = initAttribute.factor;
           
            var info = worldboss['info' + schedule.id];
            if (info) {
                info.alive_time = 0;
                info.damage_factor = initAttribute.factor;
            }

            worldboss.kill = 0;
            worldboss.kill_reward = 0;
            worldboss.top = [];
            worldboss.day = schedule.day;
            worldboss.today_id = schedule.id;

            for (var name in worldboss) {
                this.addUpdate('world_boss.'+name, worldboss[name]);
            }
            this.save();
            return true;
        }
        
        return false;
    },

    getBoss: function() {
        return this.worldboss;
    },

    addUpdate: function(key, value) {
        this.updates[key] = value;
    },

    save: function(callback) {
        if( Object.keys(this.updates).length == 0 ) {
            return;
        }    
             
        gDBWorld.update({_id : 'world_boss'}, {$set: this.updates}, function(err, result){ 
            if( err ) {
                callback && callback(false);
            }else {
                callback && callback(true);
            }    
        });  

        this.updates = {};   
    },

    getTodayBossAttrbute: function() {
        var worldboss = this.worldboss;
        var schedule = this.schedule;

        var day = (new Date()).getDayPassed(gConfGlobalServer.ServerStartTime);
        var blood = Math.min(gConfGlobal.WorldBossMaxHealth, gConfGlobal.WorldBossHealthPerDay * day);
        var factor = 1;

        var round = ALIVE_ROUND_MAX;
        var info = worldboss['info' + schedule.id];
        if (info) {
            if (info.alive_time) {
                round = Math.ceil(info.alive_time/gConfGlobal.WorldBossCoolTime);
                round = Math.min(ALIVE_ROUND_MAX, Math.max(1, round));
            }
            factor = info.damage_factor;
        }

        if (round > ALIVE_ROUND_EXPECT) {
            blood = Math.floor(blood * (1.2 - round*0.05));
            factor = factor * round*(0.25 - round*0.01);
        } else {
            factor = factor * round/ALIVE_ROUND_EXPECT;
        }

        return {'blood': blood, 'factor': factor};
    },

    addHurt: function(uid, hurt) {
        var hurts = this.hurts;
        var newUser = false;
        if( uid in hurts ) {
            hurts[uid] += hurt;
        }else{
            newUser = true;
            hurts[uid] = hurt;
        }

        var nowTime = common.getTime();
        var sortTime = this.sortTime || 0;
        var worldboss = this.worldboss;

        var confWorldBoss = gConfWorldBoss[1];
        var confMonster = gConfMonster[confWorldBoss.Boss];
        var bossBloodLeft =  worldboss.blood / worldboss.init_blood;

        if( (nowTime - sortTime) >= 60 || worldboss.kill || newUser || bossBloodLeft < 0.1 ) { 
            var top = [];
            for( var uid in hurts ) {
                var userInfo = gUserInfo.getUser(uid);
                top.push({'uid':uid, 'hurt':hurts[uid]});
            }

            top.sort(function(obj1, obj2){
                return obj2.hurt - obj1.hurt;
            });

            worldboss.top = top;

            this.sortTime = nowTime; 
            this.addUpdate('world_boss.top', worldboss.top);
        }
    },
}   

exports.get = function(req, resp, onHandled) {
    resp.nolog = 1;
    do{
        var uid = req.uid;
        var confWorldBoss = gConfWorldBoss[1];
        gWorldBoss.updateBoss();

        var worldboss = gWorldBoss.getBoss();
        var killReward = 0;
        var killName = '';
        var joinReward = 0;
        var rank5 = [];

        if( worldboss.kill ) {
            var top = worldboss.top.slice(0,5);
            top.forEach(function(obj) {
                var userInfo = gUserInfo.getUser(obj.uid);
                rank5.push({'name': userInfo.name, 'headpic': userInfo.headpic } ); 
            });

            // 参与奖
            var top = worldboss.top;
            for( var i=1,len=top.length; i<=len; i++ ) {
                if( uid == top[i-1].uid ) {
                    break;
                }
            }

            var myRankType = 0;
            if( i == 1 ) {
                myRankType = 1;
            }else if( i <= 10 ) {
                myRankType = 2;
            }else if( i <= 50 ) {
                myRankType = 3;
            }else {
                myRankType = 4;
            }

            if( i == len+1 ) {
                joinReward = 0;
            }else {
                var gotRewardBoss = worldboss.day +''+worldboss.today_id;
                if( req.args.join == worldboss.day && req.args.today_id == worldboss.today_id
                    && req.args.got_reward != gotRewardBoss ) {

                    joinReward = myRankType;
                } else if(req.args.join == worldboss.day && req.args.got_reward == gotRewardBoss ) {
                    joinReward = -myRankType;
                } else {
                    joinReward = 0; 
                }
            }

            // 击杀奖
            if( worldboss.kill ) {
                var userInfo = gUserInfo.getUser(worldboss.kill);
                killName = userInfo.name; 
            }

            if( req.uid != worldboss.kill ) {
                killReward = 0;
            }else {
                killReward = worldboss.kill_reward;
            }
        }

        resp.data.bossid = worldboss.day;
        resp.data.today_id = worldboss.today_id;
        resp.data.kill_reward = killReward;
        resp.data.kill_name = killName;
        resp.data.join_reward = joinReward;
        resp.data.rank5 = rank5;
        resp.data.init_blood = worldboss.init_blood;
        resp.data.worldboss = worldboss;

        gWorldBoss.save();

    }while(false);

    onHandled();
}

exports.rank = function(req, resp, onHandled) {
    do {  
        var uid = req.uid;
        var selfHurt = 0;
        var worldboss = gWorldBoss.getBoss();
        var rankUserInfo = [];
        worldboss.top.forEach(function(obj) {
            if( uid == obj.uid ) {
                selfHurt = obj.hurt;
            }

            var userInfo = gUserInfo.getUser(obj.uid);
            rankUserInfo.push({'name': userInfo.name});
        });

        resp.data.rank = worldboss.top.slice(0, gConfGlobal.WorldBossRankLimit);        
        resp.data.user_info = rankUserInfo;
        resp.data.self_hurt = selfHurt;
        resp.data.init_blood = worldboss.init_blood;

    }while(false) ;
    
    onHandled();
} 

exports.get_kill_reward = function(req, resp, onHandled) {
    do {
        var worldboss = gWorldBoss.getBoss();
        if( worldboss.kill != req.uid || worldboss.kill_reward != 1 ) {
            resp.code = 1; resp.desc = 'no reward'; break;
        }

        worldboss.kill_reward = -1;
        gWorldBoss.addUpdate('world_boss.kill_reward', -1);

        gWorldBoss.save();

    }while(false); 

    onHandled();
}

exports.get_reward = function(req, resp, onHandled) {
    do {
        var worldboss = gWorldBoss.getBoss();

        if( !worldboss.kill) {
            resp.code=1; resp.desc='no worldboss or kill'; break;
        }

        var gotRewardBoss = worldboss.day + '' + worldboss.today_id;
        if( req.args.got_reward == gotRewardBoss ) {
            resp.code= 1; resp.desc='got';break;
        }
        
        var rank = 0;
        var top = worldboss.top;
        for( var i=1,len=top.length; i<=len; i++ ) {
            if( req.uid == top[i-1].uid ) {
                rank = i;
                break;
            }
        }

        if( rank <= 0 ) {
            resp.code=1; resp.desc='not join'; break;
        }
        
        var rewardRank = 1;
        if( rank == 1 ) {
            rewardRank = 1;
        }else if( rank <= 10 ) {
            rewardRank = 2;
        }else if( rank <= 50 ) {
            rewardRank = 10;
        }else {
            rewardRank = 50;
        }

        var worldBossRewardConf = gConfWorldBossReward[getThisWeek()][rewardRank];

        var awards = [];
        if( worldBossRewardConf ) {
            awards = [worldBossRewardConf.Award1, worldBossRewardConf.Award2, worldBossRewardConf.Award3];
        }

        resp.data.bossid = gotRewardBoss;
        resp.data.awards = awards;

    }while(false);
    
    onHandled();
}

exports.fight = function(req, resp, onHandled) {
    do {
        var uid = req.uid;
        var worldboss = gWorldBoss.getBoss();
        if( req.args.join != worldboss.day || req.args.today_id != worldboss.today_id ) {
            resp.code = 1; resp.desc = 'not ever update user data'; break;
        }

        if( worldboss.kill ) {
            resp.data.killed = 1; break;
        }
        
        var oldBossBlood = worldboss.blood;
        var worldbossConf = gConfWorldBoss[1];
        fightWorldBoss(uid, worldbossConf, worldboss, function(battleReport) {
            if( !battleReport ) {
                resp.code = 1; resp.desc = 'fight worldboss error';
                onHandled();
                return;
            }

            var bloodLeft = battleReport.def_remain_health;
            var hurt = oldBossBlood - bloodLeft;
            worldboss.blood = bloodLeft;
            worldboss.fight_times++;
            gWorldBoss.addUpdate('world_boss.blood', worldboss.blood);
            gWorldBoss.addUpdate('world_boss.fight_times', worldboss.fight_times);
            gWorldBoss.addHurt(uid, hurt);

            if (battleReport.success || (bloodLeft <= 0)) {
                worldboss.kill = uid;
                gWorldBoss.addUpdate('world_boss.kill', uid ); 
               
                var now = new Date();
                var startTime = now.zeroTime().getStamp() + gConfGlobal['WorldBossStartHour'+worldboss.today_id]*3600 - 10;
                var aliveTime = Math.max(1, now.getStamp() - startTime);
                var infoName = 'info' + worldboss.today_id;
                var info = worldboss[infoName];
                if (info) {
                    info.alive_time = aliveTime;
                    gWorldBoss.addUpdate('world_boss.' + infoName, info); 
                }
                
                worldboss.kill_reward = 1;
                gWorldBoss.addUpdate('world_boss.kill_reward', 1);

                gMessage.addSystemMessage('world_boss_kill', [gUserInfo.getUser(uid).name]);
            }   

            resp.data.battle = battleReport;
            resp.data.time = common.getTime();

            gWorldBoss.save();  
            onHandled();
        });

        return;
    }while(false);

    onHandled();
}

exports.boss_blood = function(req, resp, onHandled) {
    do{
        var worldboss = gWorldBoss.getBoss();
        if( req.args.join != worldboss.day || req.args.today_id != worldboss.today_id ) {
            resp.code = 1; resp.desc = 'not ever update user data'; break;
        }

        resp.data.blood = worldboss.blood; 
        resp.data.killed = worldboss.blood>0 ? 0 : 1; 

    }while(false);

    onHandled();
}

function getThisWeek() {
    var maxWeek = 1;
    for( var week in gConfWorldBossReward ) { 
        if( maxWeek < week ) { 
            maxWeek = week;
        }   
    }   

    var today = new Date();
    var thisWeek = Math.ceil((Math.ceil((today/1000 - gConfGlobalServer.ServerStartTime )/86400) - gConfGlobal.WorldBossOpenDays)/7);

    if( thisWeek <= 0 ) { 
        thisWeek = 1;
    }   

    if( thisWeek > maxWeek ) { 
        thisWeek = maxWeek;
    }   

    return thisWeek;
}

exports.WorldBoss = WorldBoss;
